package com.liuwa.sms.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cloud.apigateway.sdk.utils.Client;
import com.cloud.apigateway.sdk.utils.Request;
import com.huaweicloud.sdk.core.Constants;
import com.liuwa.common.exception.ServiceException;
import com.liuwa.sms.exception.SmsException;
import com.liuwa.sms.service.SmsService;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.net.ssl.SSLContext;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;


/**
 * @Author: Liuwa
 * @Description: 华为云短信服务
 * @Date: 2024/3/8
 */
@Service("hwSmsService")
public class HwSmsService implements SmsService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * API 地址
     */
    @Value("${hwsms.api.url:https://smsapi.cn-north-4.myhuaweicloud.com}")
    private String apiUrl;

    /**
     * APP KEY
     */
    @Value("${hwsms.app.key}")
    private String appKey;

    /**
     * APP SECRET
     */
    @Value("${hwsms.app.secret}")
    private String appSecret;

    /**
     * 签名通道号
     */
    @Value("${hwsms.channel}")
    private String channel;


    /**
     * 模板ID
     */
    @Value("${hwsms.template}")
    private String templateId;

    /**
     * 签名
     */
    @Value("${hwsms.signature}")
    private String signature;

    public void sendCode(String phone, String code) {
        try{


            String url =  apiUrl + "/sms/batchSendSms/v1";
            //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
            String statusCallBack = "";

            String templateParas = "[\""+ code +"\"]";
            //请求Body,不携带签名名称时,signature请填null
            String body = buildRequestBody(channel, "+86" + phone, templateId, templateParas, statusCallBack, signature);

            Request request = new Request();
            request.setKey(appKey);
            request.setSecret(appSecret);
            request.setMethod("POST");
            request.setUrl(url);
            request.addHeader("Content-Type", "application/x-www-form-urlencoded");
            request.setBody(body);
            logger.info("Print the body: {}", body);


            HttpRequestBase signedRequest = Client.sign(request, Constants.SDK_HMAC_SHA256);
            logger.info("Print the authorization: {}", Arrays.toString(signedRequest.getHeaders("Authorization")));
            Header[] requestAllHeaders = signedRequest.getAllHeaders();
            for (Header h : requestAllHeaders) {
                logger.info("req Header with name: {} and value: {}", h.getName(), h.getValue());
            }

            CloseableHttpClient client =  createIgnoreSSLHttpClient();

            HttpResponse response = client.execute(signedRequest);

            logger.info("Print the status line of the response: {}", response.getStatusLine().toString());
            Header[] resHeaders = response.getAllHeaders();
            for (Header h : resHeaders) {
                logger.info("Processing Header with name: {} and value: {}", h.getName(), h.getValue());
            }
            HttpEntity resEntity = response.getEntity();
            if (resEntity != null) {
                String respContent = EntityUtils.toString(resEntity, "UTF-8");
                JSONObject respJson = JSON.parseObject(respContent);

                logger.info("Processing Body with name: {} and value: {}", System.getProperty("line.separator"), respContent);
                if("000000".equals(respJson.getString("code"))){
                   return ;
                }
                logger.error(respJson.getString("description"));
                throw new SmsException("发送短信失败");
            }
        }
        catch (SmsException ex){
            throw ex;
        }
        catch (Exception e) {

            logger.error(e.getMessage(), e);
            throw new SmsException("发送短信失败");
        }

    }


    public static CloseableHttpClient createIgnoreSSLHttpClient() throws Exception {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (x509CertChain, authType) -> true).build();
        return HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
    }

    String buildRequestBody(String sender, String receiver, String templateId, String templateParas,
                                   String statusCallBack, String signature)  {
        if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty()
                || templateId.isEmpty()) {
            throw new ServiceException("buildRequestBody(): sender, receiver or templateId is null.");
        }

        StringBuilder body = new StringBuilder();
        appendToBody(body, "from=", sender);
        appendToBody(body, "&to=", receiver);
        appendToBody(body, "&templateId=", templateId);
        appendToBody(body, "&templateParas=", templateParas);
        appendToBody(body, "&statusCallback=", statusCallBack);
        appendToBody(body, "&signature=", signature);
        return body.toString();
    }

    private void appendToBody(StringBuilder body, String key, String val) {
        if (null != val && !val.isEmpty()) {
            logger.info("Print appendToBody: {}:{}", key, val);
            try{
                val = URLEncoder.encode(val, "utf-8");
            }
            catch (UnsupportedEncodingException ex ){
                logger.error(ex.getMessage(), ex);
            }
            body.append(key).append(val);
        }
    }
}
